#!/usr/bin/env ruby
# https://rubygems.org/gems/diffy
require "diffy"
require "open-uri"
require "yaml"

Diffy::Diff.default_options.merge!(
  include_diff_info: true,
  context: 1,
)

class Tarball
  attr_reader :version, :size, :sha1, :sha256, :sha512

  def initialize(version, url, size, sha1, sha256, sha512)
    @url = url
    @size = size
    @sha1 = sha1
    @sha256 = sha256
    @sha512 = sha512
    @version = version
    @xy = version[/\A\d+\.\d+/]
  end

  def gz?;  @url.end_with?('.gz'); end
  def zip?; @url.end_with?('.zip'); end
  def bz2?; @url.end_with?('.bz2'); end
  def xz?;  @url.end_with?('.xz'); end

  def ext; @url[/(?:zip|tar\.(?:gz|bz2|xz))\z/]; end

  def to_md
    <<eom
* <https://cache.ruby-lang.org/pub/ruby/#{@xy}/ruby-#{@version}.#{ext}>

      SIZE:   #{@size} bytes
      SHA1:   #{@sha1}
      SHA256: #{@sha256}
      SHA512: #{@sha512}
eom
  end

  # * /home/naruse/obj/ruby-trunk/tmp/ruby-2.6.0-preview3.tar.gz
  #   SIZE:   17116009 bytes
  #   SHA1:   21f62c369661a2ab1b521fd2fa8191a4273e12a1
  #   SHA256: 97cea8aa63dfa250ba6902b658a7aa066daf817b22f82b7ee28f44aec7c2e394
  #   SHA512: 1e2042324821bb4e110af7067f52891606dcfc71e640c194ab1c117f0b941550e0b3ac36ad3511214ac80c536b9e5cfaf8789eec74cf56971a832ea8fc4e6d94
  def self.parse(wwwdir, version)
    unless /\A(\d+)\.(\d+)\.(\d+)(?:-(?:preview|rc)\d+)?\z/ =~ version
      raise "unexpected version string '#{version}'"
    end
    x = $1.to_i
    y = $2.to_i
    z = $3.to_i
    # previous tag for git diff --shortstat
    # It's only for x.y.0 release
    if z != 0
      prev_tag = nil
    elsif y != 0
      prev_tag = "v#{x}_#{y-1}_0"
      prev_ver = "#{x}.#{y-1}.0"
    elsif x == 3 && y == 0 && z == 0
      prev_tag = "v2_7_0"
      prev_ver = "2.7.0"
    else
      raise "unexpected version for prev_ver '#{version}'"
    end

    uri = "https://cache.ruby-lang.org/pub/tmp/ruby-info-#{version}-draft.yml"
    info = YAML.load(URI(uri).read)
    if info.size != 1
      raise "unexpected info.yml '#{uri}'"
    end
    tarballs = []
    info[0]["size"].each_key do |ext|
      url = info[0]["url"][ext]
      size = info[0]["size"][ext]
      sha1 = info[0]["sha1"][ext]
      sha256 = info[0]["sha256"][ext]
      sha512 = info[0]["sha512"][ext]
      tarball = Tarball.new(version, url, size, sha1, sha256, sha512)
      tarballs << tarball
    end

    if prev_tag
      # show diff shortstat
      tag = "v#{version.gsub(/[.\-]/, '_')}"
      stat = `git diff --shortstat #{prev_tag}..#{tag}`
      files_changed, insertions, deletions = stat.scan(/\d+/)
    end

    xy = version[/\A\d+\.\d+/]
    #puts "## Download\n\n"
    #tarballs.each do |tarball|
    #  puts tarball.to_md
    #end
    update_branches_yml(version, xy, wwwdir)
    update_downloads_yml(version, xy, wwwdir)
    update_releases_yml(version, xy, tarballs, wwwdir, files_changed, insertions, deletions)
    tarballs
  end

  def self.update_branches_yml(ver, xy, wwwdir)
    filename = "_data/branches.yml"
    orig_data = File.read(File.join(wwwdir, filename))
    data = orig_data.dup
    if data.include?("\n- name: #{xy}\n")
      data.sub!(/\n- name: #{Regexp.escape(xy)}\n(?:  .*\n)*/) do |node|
        unless ver.include?("-")
          # assume this is X.Y.0 release
          node.sub!(/^  status: preview\n/, "  status: normal maintenance\n")
          node.sub!(/^  date:\n/, "  date: #{Time.now.year}-12-25\n")
        end
        node
      end
    else
      if ver.include?("-")
        status = "preview"
        year = nil
      else
        status = "normal maintenance"
        year = Time.now.year
      end
      entry = <<eom
- name: #{xy}
  status: #{status}
  date:#{ year && " #{year}-12-25" }
  eol_date:

eom
      data.sub!(/(?=^- name)/, entry)
    end
    if data != orig_data
      diff = Diffy::Diff.new(orig_data, data)
      show_diff(filename, diff)
    end
  end

  def self.update_downloads_yml(ver, xy, wwwdir)
    filename = "_data/downloads.yml"
    orig_data = File.read(File.join(wwwdir, filename))
    data = orig_data.dup

    if /^preview:\n\n(?:  .*\n)*  - #{Regexp.escape(xy)}\./ =~ data
      if ver.include?("-")
        data.sub!(/^  - #{Regexp.escape(xy)}\..*/, "  - #{ver}")
      else
        data.sub!(/^  - #{Regexp.escape(xy)}\..*\n/, "")
        data.sub!(/(?<=^stable:\n\n)/, "  - #{ver}\n")
      end
    else
      unless data.sub!(/^  - #{Regexp.escape(xy)}\..*/, "  - #{ver}")
        if ver.include?("-")
          data.sub!(/(?<=^preview:\n\n)/, "  - #{ver}\n")
        else
          data.sub!(/(?<=^stable:\n\n)/, "  - #{ver}\n")
        end
      end
    end
    if data != orig_data
      diff = Diffy::Diff.new(orig_data, data)
      show_diff(filename, diff)
    end
  end

  def self.update_releases_yml(ver, xy, ary, wwwdir, files_changed, insertions, deletions)
    filename = "_data/releases.yml"
    orig_data = File.read(File.join(wwwdir, filename))
    data = orig_data.dup

    date = Time.now.utc # use utc to use previous day in midnight
    entry = <<eom
- version: #{ver}
  date: #{date.strftime("%Y-%m-%d")}
  post: /en/news/#{date.strftime("%Y/%m/%d")}/ruby-#{ver.tr('.', '-')}-released/
  stats:
    files_changed: #{files_changed}
    insertions: #{insertions}
    deletions: #{deletions}
  url:
    gz:  https://cache.ruby-lang.org/pub/ruby/#{xy}/ruby-#{ver}.tar.gz
    zip: https://cache.ruby-lang.org/pub/ruby/#{xy}/ruby-#{ver}.zip
    bz2: https://cache.ruby-lang.org/pub/ruby/#{xy}/ruby-#{ver}.tar.bz2
    xz:  https://cache.ruby-lang.org/pub/ruby/#{xy}/ruby-#{ver}.tar.xz
  size:
    gz:  #{ary.find{|x|x.gz? }.size}
    zip: #{ary.find{|x|x.zip?}.size}
    bz2: #{ary.find{|x|x.bz2?}.size}
    xz:  #{ary.find{|x|x.xz? }.size}
  sha1:
    gz:  #{ary.find{|x|x.gz? }.sha1}
    zip: #{ary.find{|x|x.zip?}.sha1}
    bz2: #{ary.find{|x|x.bz2?}.sha1}
    xz:  #{ary.find{|x|x.xz? }.sha1}
  sha256:
    gz:  #{ary.find{|x|x.gz? }.sha256}
    zip: #{ary.find{|x|x.zip?}.sha256}
    bz2: #{ary.find{|x|x.bz2?}.sha256}
    xz:  #{ary.find{|x|x.xz? }.sha256}
  sha512:
    gz:  #{ary.find{|x|x.gz? }.sha512}
    zip: #{ary.find{|x|x.zip?}.sha512}
    bz2: #{ary.find{|x|x.bz2?}.sha512}
    xz:  #{ary.find{|x|x.xz? }.sha512}
eom

    if data.include?("\n- version: #{ver}\n")
    elsif data.sub!(/\n# #{Regexp.escape(xy)} series\n/, "\\&\n#{entry}")
    else
      data.sub!(/^$/, "\n# #{xy} series\n\n#{entry}")
    end
    if data != orig_data
      diff =  Diffy::Diff.new(orig_data, data)
      show_diff(filename, diff)
    end
  end

  def self.show_diff(filename, diff)
    diff.each_with_index do |line, index|
      case index
      when 0
        line.sub!(/\A--- (.*)\t(\d+-\d+-\d+ [0-9:.]+ [\-+]\d+)\Z/) do
          "--- a/#{filename}\t#{$2}"
        end
      when 1
        line.sub!(/\A\+\+\+ (.*)\t(\d+-\d+-\d+ [0-9:.]+ [\-+]\d+)\Z/) do
          "+++ b/#{filename}\t#{$2}"
        end
      end
      puts line
    end
  end
end

def main
  if ARGV.size != 2
    STDERR.puts "usage: format-release <dir-of-w.r-l.o> <version>"
    exit
  end
  wwwdir = ARGV.shift
  version = ARGV.shift
  Tarball.parse(wwwdir, version)
end

main
